--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -36,12 +36,15 @@ struct omap_crtc {
 
 	struct videomode vm;
 
-	bool ignore_digit_sync_lost;
+	bool ignore_sync_lost;
 
 	bool enabled;
 	bool pending;
 	wait_queue_head_t pending_wait;
 	struct drm_pending_vblank_event *event;
+
+	struct work_struct error_work;
+	u32 error_channels;
 };
 
 /* -----------------------------------------------------------------------------
@@ -157,7 +160,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
 		 * Digit output produces some sync lost interrupts during the
 		 * first frame when enabling, so we need to ignore those.
 		 */
-		omap_crtc->ignore_digit_sync_lost = true;
+		omap_crtc->ignore_sync_lost = true;
 	}
 
 	framedone_irq = priv->dispc_ops->mgr_get_framedone_irq(channel);
@@ -191,7 +194,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
 	}
 
 	if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
-		omap_crtc->ignore_digit_sync_lost = false;
+		omap_crtc->ignore_sync_lost = false;
 		/* make sure the irq handler sees the value above */
 		mb();
 	}
@@ -263,17 +266,65 @@ static const struct dss_mgr_ops mgr_ops = {
  * Setup, Flush and Page Flip
  */
 
+static void omap_crtc_error_worker(struct work_struct *work)
+{
+	struct omap_crtc *omap_crtc = container_of(work, struct omap_crtc, error_work);
+	struct drm_crtc *crtc = &omap_crtc->base;
+	struct drm_device *dev = omap_crtc->base.dev;
+	struct omap_drm_private *priv = dev->dev_private;
+
+	drm_modeset_lock(&crtc->mutex, NULL);
+
+	dev_warn(dev->dev, "sync lost on %s, enabling & disabling...\n",
+		omap_crtc->name);
+
+	priv->dispc_ops->mgr_enable(omap_crtc->channel, false);
+
+	msleep(50);
+	dev_warn(dev->dev, "sync lost enabling %s\n",
+			omap_crtc->name);
+
+	priv->dispc_ops->mgr_enable(omap_crtc->channel, true);
+
+	msleep(50);
+
+	dev_warn(dev->dev, "sync lost recovery done on on %s\n",
+		omap_crtc->name);
+
+	omap_crtc->ignore_sync_lost = false;
+	/* make sure the irq handler sees the value above */
+	mb();
+
+	drm_modeset_unlock(&crtc->mutex);
+}
+
 void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus)
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+	struct drm_device *dev = omap_crtc->base.dev;
+	struct omap_drm_private *priv = dev->dev_private;
+	enum omap_channel channel = omap_crtc_channel(crtc);
+	u32 sync_lost_irq;
+	bool sync_lost;
+
+	sync_lost_irq = priv->dispc_ops->mgr_get_sync_lost_irq(channel);
 
-	if (omap_crtc->ignore_digit_sync_lost) {
-		irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
-		if (!irqstatus)
-			return;
+	sync_lost = irqstatus & sync_lost_irq;
+
+	if (sync_lost) {
+		if (omap_crtc->ignore_sync_lost) {
+			irqstatus &= ~sync_lost_irq;
+		} else {
+			/* error worker will set this to false */
+			omap_crtc->ignore_sync_lost = true;
+			schedule_work(&omap_crtc->error_work);
+		}
 	}
 
-	DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
+	if (!irqstatus)
+		return;
+
+	printk("%s: errors: %08x\n", omap_crtc->name, irqstatus);
 }
 
 void omap_crtc_vblank_irq(struct drm_crtc *crtc)
@@ -612,6 +663,8 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 
 	init_waitqueue_head(&omap_crtc->pending_wait);
 
+	INIT_WORK(&omap_crtc->error_work, omap_crtc_error_worker);
+
 	omap_crtc->channel = channel;
 	omap_crtc->name = channel_names[channel];
